`include "../codigo/Fetch.v"
`include "../codigo/Decode.v"
`include "../codigo/Execute.v"
`include "../codigo/Memory.v"
`include "../codigo/Writeback.v"
`include "../codigo/Registers.v"
`include "../codigo/Forwarding.v"


module Mips (

	input			clock,
	input			reset,

	// Fetch <-> MC
	output			if_mc_en,
	output	[31:0]	if_mc_addr,	
	input	[31:0]	mc_if_data,

	// Memory <-> MC
	output			mem_mc_rw,
	output			mem_mc_en,
	output	[31:0]	mem_mc_addr, 
	inout	[31:0]	mem_mc_data,
	output			mem_mc_en1h,
	output			mem_mc_en1l,
	output			mem_mc_en2h,
	output			mem_mc_en2l
	
	);

	// Fios de saída: Fetch
	wire	[31:0]	if_id_proximopc;
	wire	[31:0]	if_id_instrucao; 
//	wire			if_mc_en;
//	wire	[31:0]	if_mc_addr;

	// Fios de saída: Decode.
	wire	[31:0]	id_if_pcimd2ext;
	wire	[31:0]	id_if_pcindex;
	wire	[31:0]	id_if_rega;
	wire			id_if_selfontepc;
	wire	[1:0]	id_if_seltipopc;
	wire			id_ex_selalushift;
	wire			id_ex_selimregb;
	wire			id_ex_selsarega;
	wire	[2:0]	id_ex_aluop;
	wire 			id_ex_unsig;
	wire	[1:0]	id_ex_shiftop;
	wire	[4:0]	id_ex_shiftamt;
	wire	[31:0]	id_ex_rega;
	wire	[2:0]	id_ex_msm;
	wire	[2:0]	id_ex_msl;
	wire			id_ex_readmem;
	wire			id_ex_writemem;
	wire			id_ex_mshw;
	wire			id_ex_lshw;
	wire	[31:0]	id_ex_regb;
	wire	[31:0]	id_ex_imedext;
	wire	[31:0]	id_ex_proximopc;
	wire	[2:0]	id_ex_selwsource;
	wire	[4:0]	id_ex_regdest;
	wire			id_ex_writereg;
	wire			id_ex_writeov;
	wire	[4:0]	id_fw_regdest;
	wire			id_fw_load;
	wire	[4:0]	id_fw_addra;
	wire	[4:0]	id_fw_addrb;
	wire	[31:0]	id_fw_rega;
	wire	[31:0]	id_fw_regb;
	wire	[4:0]	id_reg_addra;
	wire	[4:0]	id_reg_addrb;
	wire			id_reg_ena;
	wire			id_reg_enb;

	// Fios de saída: Execute.
	wire	[31:0]	ex_fw_wbvalue; 
	wire			ex_if_stall;
	wire	[2:0]	ex_mem_msm;
	wire	[2:0]	ex_mem_msl;
	wire			ex_mem_readmem;    
	wire			ex_mem_writemem;   
	wire			ex_mem_mshw;
	wire			ex_mem_lshw;
	wire	[31:0]	ex_mem_regb;
	wire	[2:0]	ex_mem_selwsource;
	wire	[4:0]	ex_mem_regdest; 
	wire			ex_mem_writereg; 
	wire	[31:0]	ex_mem_aluout; 
	wire	[31:0]	ex_mem_wbvalue;
	
	// Fios de saída: Memory.
	wire			mem_mc_rw;
	wire			mem_mc_en;
	wire	[31:0] 	mem_mc_addr;
	wire	[31:0] 	mem_mc_data;
	wire			mem_mc_en1h;
	wire			mem_mc_en1l;
	wire			mem_mc_en2h;
	wire			mem_mc_en2l;
	wire	[31:0] 	mem_fw_wbvalue;
	wire			mem_fw_writereg;
	wire	[4:0] 	mem_wb_regdest;
	wire			mem_wb_writereg;
	wire	[31:0] 	mem_wb_wbvalue;

	// Fios saida: Forwarding
	wire			fw_if_id_stall;
	wire	[31:0]	fw_id_rega;
	wire	[31:0]	fw_id_regb;

	// Fios saida: Registers
	wire	[31:0]	reg_id_dataa;
	wire	[31:0]	reg_id_datab;

	// Fios saida: Writeback
	wire			wb_reg_en;
	wire	[4:0]	wb_reg_addr;
	wire	[31:0]	wb_reg_data;
	wire	[31:0]	wb_fw_wbvalue;
	wire			wb_fw_writereg;


	// Busca da instrução.
	Fetch FETCH(
		.clock				(clock),
		.reset				(reset),
		.ex_if_stall		(ex_if_stall),
		.fw_if_id_stall		(fw_if_id_stall),
		.if_id_proximopc	(if_id_proximopc),
		.if_id_instrucao	(if_id_instrucao),
		.id_if_selfontepc	(id_if_selfontep),
		.id_if_rega			(id_if_rega),
		.id_if_pcimd2ext	(id_if_pcimd2ext),
		.id_if_pcindex		(id_if_pcindex),
		.id_if_seltipopc	(id_if_seltipopc),
		.if_mc_en			(if_mc_en),
		.if_mc_addr			(if_mc_addr),
		.mc_if_data			(mc_if_data)
	);


	// Decodificação da instrução.
	Decode DECODE(
		.clock            (clock),
		.reset            (reset),
		.fw_if_id_stall   (fw_if_id_stall),
		.if_id_instrucao  (if_id_instrucao),
		.if_id_proximopc  (if_id_proximopc),
		.id_if_selfontepc (id_if_selfontepc),
		.id_if_rega       (id_if_rega),
		.id_if_pcimd2ext  (id_if_pcimd2ext),
		.id_if_pcindex    (id_if_pcindex),
		.id_if_seltipopc  (id_if_seltipopc),
		.id_ex_selalushift(id_ex_selalushift),
		.id_ex_selimregb  (id_ex_selimregb),
		.id_ex_selsarega  (id_ex_selsarega),
		.id_ex_aluop      (id_ex_aluop),
		.id_ex_unsig      (id_ex_unsig),
		.id_ex_shiftop    (id_ex_shiftop),
		.id_ex_shiftamt   (id_ex_shiftamt),
		.id_ex_rega       (id_ex_rega),
		.id_ex_msm        (id_ex_msm),
		.id_ex_msl        (id_ex_msl),
		.id_ex_readmem    (id_ex_readmem),
		.id_ex_writemem   (id_ex_writemem),
		.id_ex_mshw       (id_ex_mshw),
		.id_ex_lshw       (id_ex_lshw),
		.id_ex_regb       (id_ex_regb),
		.id_ex_imedext    (id_ex_imedext),
		.id_ex_proximopc  (id_ex_proximopc),
		.id_ex_selwsource (id_ex_selwsource),
		.id_ex_regdest    (id_ex_regdest),
		.id_ex_writereg   (id_ex_writereg),
		.id_ex_writeov    (id_ex_writeov),
		.id_fw_regdest    (id_fw_regdest),
		.id_fw_load       (id_fw_load),
		.id_fw_addra      (id_fw_addra),
		.id_fw_addrb      (id_fw_addrb),
		.id_fw_rega       (id_fw_rega),
		.id_fw_regb       (id_fw_regb),
		.fw_id_rega       (fw_id_rega),
		.fw_id_regb       (fw_id_regb),
		.id_reg_addra     (id_reg_addra),
		.id_reg_addrb     (id_reg_addrb),
		.reg_id_dataa     (reg_id_dataa),
		.reg_id_datab     (reg_id_datab),
		.id_reg_ena       (id_reg_ena),
		.id_reg_enb       (id_reg_enb)
	);


	// Execução.
	Execute EXECUTE(
		.clock(clock),
		.reset(reset),
		.id_ex_selalushift(id_ex_selalushift),
		.id_ex_selimregb(id_ex_selimregb),
		.id_ex_selsarega(id_ex_selsarega),
		.id_ex_aluop(id_ex_aluop),
		.id_ex_unsig(id_ex_unsig),
		.id_ex_shiftop(id_ex_shiftop),    
		.id_ex_shiftamt(id_ex_shiftamt),  
		.id_ex_rega(id_ex_rega),
		.id_ex_msm(id_ex_msm),
		.id_ex_msl(id_ex_msl),
		.id_ex_readmem(id_ex_readmem),    
		.id_ex_writemem(id_ex_writemem),  
		.id_ex_mshw(id_ex_mshw),
		.id_ex_lshw(id_ex_lshw),
		.id_ex_regb(id_ex_regb),
		.id_ex_imedext(id_ex_imedext),
		.id_ex_proximopc(id_ex_proximopc),
		.id_ex_selwsource(id_ex_selwsource),  
		.id_ex_regdest(id_ex_regdest), 
		.id_ex_writereg(id_ex_writereg),
		.id_ex_writeov(id_ex_writeov),  
		.ex_fw_wbvalue(ex_fw_wbvalue),  
		.ex_fw_writereg(ex_fw_writereg),
		.ex_if_stall(ex_if_stall),
		.ex_mem_msm(ex_mem_msm),
		.ex_mem_msl(ex_mem_msl),
		.ex_mem_readmem(ex_mem_readmem),
		.ex_mem_writemem(ex_mem_writemem),
		.ex_mem_mshw(ex_mem_mshw),
		.ex_mem_lshw(ex_mem_lshw),
		.ex_mem_regb(ex_mem_regb),
		.ex_mem_selwsource(ex_mem_selwsource),
		.ex_mem_regdest(ex_mem_regdest),
		.ex_mem_writereg(ex_mem_writereg),
		.ex_mem_aluout(ex_mem_aluout),
		.ex_mem_wbvalue(ex_mem_wbvalue)
	);


	// Acesso à memória.
	
	Memory MEMORY(
		.clock(clock),
		.reset(reset),
		.ex_mem_msm(ex_mem_msm),
		.ex_mem_msl(ex_mem_msl),
		.ex_mem_readmem(ex_mem_readmem),
		.ex_mem_writemem(ex_mem_writemem),
		.ex_mem_mshw(ex_mem_mshw),
		.ex_mem_lshw(ex_mem_lshw),
		.ex_mem_regb(ex_mem_regb),
		.ex_mem_selwsource(ex_mem_selwsource),
		.ex_mem_regdest(ex_mem_regdest),
		.ex_mem_writereg(ex_mem_writereg),
		.ex_mem_aluout(ex_mem_aluout),
		.ex_mem_wbvalue(ex_mem_wbvalue),
		.mem_mc_rw(mem_mc_rw),
		.mem_mc_en(mem_mc_en),
		.mem_mc_addr(mem_mc_addr),
		.mem_mc_data(mem_mc_data),
		.mem_mc_en1h(mem_mc_en1h),
		.mem_mc_en1l(mem_mc_en1l),
		.mem_mc_en2h(mem_mc_en2h),
		.mem_mc_en2l(mem_mc_en2l),
		.mem_fw_wbvalue(mem_fw_wbvalue),
		.mem_fw_writereg(mem_fw_writereg),
		.mem_wb_regdest(mem_wb_regdest),
		.mem_wb_writereg(mem_wb_writereg),
		.mem_wb_wbvalue(mem_wb_wbvalue)
	);



	// Escrita no banco de registradores.
	Writeback WRITEBACK(
		.clock(clock),
		.mem_wb_regdest(mem_wb_regdest),
		.mem_wb_writereg(mem_wb_writereg),
		.mem_wb_wbvalue(mem_wb_wbvalue),
		.wb_reg_en(w_wb_reg_en),
		.wb_reg_addr(wb_reg_addr),
		.wb_reg_data(wb_reg_data),
		.wb_fw_wbvalue(wb_fw_wbvalue),
		.wb_fw_writereg(wb_fw_writereg)
	);
	

	// Banco de registradores.
	Registers REGS(
		// input
		.reset(reset),
		.ena(id_reg_ena),
		.addra(id_reg_addra),
		.dataa(reg_id_dataa),
		.enb(id_reg_enb),
		.addrb(id_reg_addrb),
		.datab(reg_id_datab),
		.enc(wb_reg_en),
		.addrc(wb_reg_addr),
		.datac(wb_reg_data)
	);

	
	// Unidade de encaminhamento.
	Forwarding FW(
		.clock(clock),
		.reset(reset),
		.fw_if_id_stall(fw_if_id_stall), 
		.id_fw_regdest(id_fw_regdest),  
		.id_fw_load(id_fw_load),     
		.id_fw_addra(id_fw_addra),    
		.id_fw_addrb(id_fw_addrb),    
		.id_fw_rega(id_fw_rega),     
		.id_fw_regb(id_fw_regb),     
		.fw_id_rega(fw_id_rega),     
		.fw_id_regb(fw_id_regb),
		.ex_fw_wbvalue(ex_fw_wbvalue),  
		.ex_fw_writereg(ex_fw_writereg), 
		.mem_fw_wbvalue(mem_fw_wbvalue), 
		.mem_fw_writereg(mem_fw_writereg),
		.wb_fw_wbvalue(wb_fw_wbvalue),  
		.wb_fw_writereg(wb_fw_writereg)  
	);



endmodule
